package org.dromara.neutrinoproxy.client.config;


import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.socksx.v5.Socks5CommandRequestDecoder;
import io.netty.handler.codec.socksx.v5.Socks5InitialRequestDecoder;
import io.netty.handler.codec.socksx.v5.Socks5ServerEncoder;
import lombok.extern.slf4j.Slf4j;
import org.dromara.neutrinoproxy.client.socks5.Socks5CommandRequestInboundHandler;
import org.dromara.neutrinoproxy.client.socks5.Socks5InitialRequestInboundHandler;
import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Condition;
import org.noear.solon.annotation.Configuration;
import org.noear.solon.annotation.Inject;

import java.util.concurrent.CompletableFuture;

/**
 * 代理配置
 * @author: aoshiguchen
 * @date: 2022/10/8
 */
@Slf4j
@Configuration
public class ProxySocks5Configuration {

    @Bean(name = "socks5Obj")
    //@Condition(onProperty="${yyy.enable}") //有属性值
    @Condition(onProperty="${neutrino.proxy.socks5.enable:false} = true") //有属性值，且等于true
    public Object init(@Inject("${neutrino.proxy.socks5.config}") Socks5Config socks5Config) {
        log.debug("启动socks5 ing ....{}", JSONUtil.toJsonStr(socks5Config));
        CompletableFuture.runAsync(()->{
            try {
                startSocks5(socks5Config);
            } catch (Exception e) {
                log.error("socks5 常");
            }
        });
        return new Object();
    }

    private void startSocks5(Socks5Config configProperties) throws InterruptedException {
        EventLoopGroup clientWorkGroup = new NioEventLoopGroup();
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        ServerBootstrap bootstrap = new ServerBootstrap();
        try {
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 256)
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();

                            //socks5响应最后一个encode
                            pipeline.addLast(Socks5ServerEncoder.DEFAULT);

                            //处理socks5初始化请求
                            pipeline.addLast(new Socks5InitialRequestDecoder());
                            pipeline.addLast(new Socks5InitialRequestInboundHandler());

                            //处理认证请求
                            /*if(configProperties.isAuthentication()){
                                pipeline.addLast(new Socks5PasswordAuthRequestDecoder());
                                pipeline.addLast(new Socks5PasswordAuthRequestInboundHandler(configUtil));
                            }*/
                            //处理connection请求
                            pipeline.addLast(new Socks5CommandRequestDecoder());
                            pipeline.addLast(new Socks5CommandRequestInboundHandler(clientWorkGroup));
                        }
                    });
            ChannelFuture future = bootstrap.bind(configProperties.getServerPort()).sync();
            log.info("socks5 netty server has started on port {}", configProperties.getServerPort());
            future.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }


}
